package master

import (
	"context"
	"encoding/json"
	"gitee.com/xianfuxing/go-crontab/crontab/common"
	"go.etcd.io/etcd/client/v3"
	"time"
)

// JobMgr 任务管理器
type JobMgr struct {
	client *clientv3.Client
	kv     clientv3.KV
	lease  clientv3.Lease
}

var (
	// G_jobMgr 单例
	G_jobMgr *JobMgr
)

// InitJobMgr 初始化任务管理器
func InitJobMgr() (err error) {
	var (
		config clientv3.Config
		client *clientv3.Client
		kv     clientv3.KV
		lease  clientv3.Lease
	)

	// 初始化配置
	config = clientv3.Config{
		Endpoints:   G_config.EtcdEndpoints,                                     // 集群地址
		DialTimeout: time.Duration(G_config.EtcdDialTimeout) * time.Millisecond, // 超时时间
	}

	// 建立连接
	if client, err = clientv3.New(config); err != nil {
		return err
	}

	// 得到 KV 和 Lease 的 API 子集
	kv = clientv3.KV(client)
	lease = clientv3.Lease(client)

	// 复制单例
	G_jobMgr = &JobMgr{
		client: client,
		kv:     kv,
		lease:  lease,
	}

	return err
}

// SaveJob save job
func (jobMgr *JobMgr) SaveJob(job *common.Job) (oldJob *common.Job, err error) {
	// save job to /cron/jobs/任务名 -> json
	var (
		jobKey    string
		jobVale   []byte
		putResp   *clientv3.PutResponse
		oldJobObj common.Job
	)

	// etcd key
	jobKey = common.JOB_SAVE_DIR + job.Name
	if jobVale, err = json.Marshal(job); err != nil {
		return nil, err
	}
	// save to etcd
	if putResp, err = jobMgr.kv.Put(context.TODO(), jobKey, string(jobVale), clientv3.WithPrevKV()); err != nil {
		return nil, err
	}
	// if updated return old value
	if putResp.PrevKv != nil {
		// old value deserialization
		if err = json.Unmarshal(jobVale, &oldJobObj); err != nil {
			return nil, err
		}
		oldJob = &oldJobObj
	}

	return oldJob, nil
}

func (jobMgr *JobMgr) DeleteJob(name string) (oldJob *common.Job, err error) {
	var (
		jobKey    string
		delResp   *clientv3.DeleteResponse
		oldJobOjb common.Job
	)
	jobKey = common.JOB_SAVE_DIR + name
	if delResp, err = jobMgr.kv.Delete(context.TODO(), jobKey, clientv3.WithPrevKV()); err != nil {
		return nil, err
	}
	if len(delResp.PrevKvs) != 0 {
		if err = json.Unmarshal(delResp.PrevKvs[0].Value, &oldJobOjb); err != nil {
			return nil, err
		}
		oldJob = &oldJobOjb
	}
	return oldJob, nil
}
